from socket import *
import time
import ctypes
from .apis import Apis



class Broker():

    def __init__(self):
        # self._socket = socket(AF_INET, SOCK_STREAM)
        a = Apis()
        IP_ADDR = a.read_item_from_config_ini('dev', 'ip')
        self._ip = IP_ADDR
        
        # self._ip = "192.168.1.212"
        pass

    def open(self):
        self._socket = socket(AF_INET, SOCK_STREAM)
        self._socket.connect((self._ip, 1000))
        prompt = self._socket.recv(1024)
        # print(prompt.decode('gbk'))

    def close(self):
        self._socket.close()

    @property
    def IP(self):
        return self._ip

    @IP.setter
    def IP(self, val):
        self._ip = val

    @property
    def TWI_SPEED(self):
        self.open()
        self._socket.send("*twir".encode())
        rx = self._socket.recv(1024)
        self.close()
        # print(rx.decode('gbk'))
        return int(str(rx.decode('gbk')).split('>')[1].split('\\')[0], 10)

    @TWI_SPEED.setter
    def TWI_SPEED(self, val):
        self.open()
        tx = ("*twir %d" % val).encode()
        self._socket.send(tx)
        rx = self._socket.recv(1024)
        self.close()
        # print(rx.decode('gbk'))

    def parse_cmdstr(self, buffer_string):
        s1 = str(buffer_string)
        s2 = s1.split(";")
        s3 = s2[0].split("'")
        buffer_string = s3[1]
        return buffer_string

    def dcpy(self, addr, len):
        self.open()
        tx = ("*dcpy %d %d" % (addr, len)).encode()
        self._socket.send(tx)
        rx = self._socket.recv(1024)
        self.close()        
        if self.parse_cmdstr(rx) == '$0000':
            return 1
        else:
            return 0

    def twi_car(self):  # Current Address Read Operation
        self.open()
        self._socket.send("*twi 1".encode())
        rx = self._socket.recv(1024)
        self.close()
        return int(str(rx.decode('gbk')).split('>')[1].split(',')[0], 16)
    
    def twi_scar(self, len):  # Sequential Current Address Read Operation
        self.open()
        self._socket.send(("*twi %d" % len).encode())
        rx = self._socket.recv(1024)
        self.close()
        vals = str(rx.decode('gbk')).split('>')[1].split(',')
        # print(vals)
        r = bytearray()
        for i in range(len):
            r.append(int(vals[i], 16))
        return r
    
    def twi_rr(self, addr):  # Random Read Operation
        self.open()
        self._socket.send(("*twi 1 %d" % addr).encode())
        rx = self._socket.recv(1024)
        # print(rx)
        self.close()
        # print(rx.decode('gbk'))
        try:           
            return int(str(rx.decode('gbk')).split('>')[1].split(',')[0], 16)
        except Exception as e:
            print(e)
            print(rx)
            
            
           

    def twi_srr(self, addr, len):  # Sequential Random Read Operation
        self.open()
        self._socket.send(("*twi %d %d" % (len, addr)).encode())
        rx = self._socket.recv(1024)
        self.close()
        # print(rx)
        vals = str(rx.decode('gbk')).split('>')[1].split(',')
        # print(vals)
        r = bytearray()
        for i in range(len):
            r.append(int(vals[i], 16))
        return r

    def twi_bw(self, addr, val): # Byte Write Operation
        tx = "*twi 1 %d %d" % (addr, val)
        # print(tx)
        self.open()
        self._socket.send(tx.encode())
        rx = self._socket.recv(1024)
        self.close()
        # print(rx.decode('gbk'))

    def twi_sbw(self, addr, vals): # Sequential Byte Write Operation
        length = len(vals)
        # print(length)
        tx = '*twi %d %d' % (length, addr)
        for b in vals:
            tx += ' %d' % b
        # print(tx)
        self.open()
        self._socket.send(tx.encode())
        rx = self._socket.recv(1024)
        self.close()
    
    def cdb_pswdw(self): # Write CDB password: 0xa5, 0x5a, 0x5a, 0xa5 to lower memory byte 122~125
        self.twi_sbw(122, b'\xa5\x5a\x5a\xa5')

    def ain(self, id): 
        tx = '*ain %d' % id
        self.open()
        self._socket.send(tx.encode())
        rx = self._socket.recv(1024)
        self.close()
        # print(rx.decode('gbk'))
        vals = str(rx.decode('gbk')).split('>')[1].split(',')
        d = int(vals[0], 10)
        a = float(vals[1])
        return d, a

    def aout(self, id): 
        tx = '*aout %d' % id
        self.open()
        self._socket.send(tx.encode())
        rx = self._socket.recv(1024)
        self.close()
        # print(rx.decode('gbk'))
        vals = str(rx.decode('gbk')).split('>')[1].split(',')
        s = float(vals[0])
        r = float(vals[1])
        return s, r

    def aout_set(self, id, val): 
        tx = '*aout %d %f' % (id, val)
        self.open()
        self._socket.send(tx.encode())
        rx = self._socket.recv(1024)
        self.close()
        # print(rx.decode('gbk'))

    def din(self, id):
        tx = '*din %d' % id
        self.open()
        self._socket.send(tx.encode())
        rx = self._socket.recv(1024)
        self.close()
        # print(rx.decode('gbk'))
        return int(str(rx.decode('gbk')).split('>')[1].strip(), 10)

    def dout(self, id):
        tx = '*dout %d' % id
        self.open()
        self._socket.send(tx.encode())
        rx = self._socket.recv(1024)
        self.close()
        # print(rx.decode('gbk'))
        return int(str(rx.decode('gbk')).split('>')[1].strip(), 10)

    def dout_set(self, id, state):
        tx = '*dout %d %d' % (id, state)
        self.open()
        self._socket.send(tx.encode())
        rx = self._socket.recv(1024)
        self.close()
        # print(rx.decode('gbk'))

    @property
    def MOD_VOLTAGE(self):
        return self.ain(102)[1] # P3V3_OSFP_CON = 102

    @MOD_VOLTAGE.setter
    def MOD_VOLTAGE(self, val):
        self.aout_set(101, val)

    @property
    def MOD_CURRENT(self):
        return self.ain(100)[1] # P3V3_OSFP_CURR_CHECK = 100

    @property
    def MOD_INT(self):
        return not self.din(1) # MOD_INTN = 1

    @property
    def MOD_PRSn(self):
        return not self.din(2) # MOD_PRSN = 2

    @property
    def MOD_LPWn(self):
        return bool(self.dout(21)) # MOD_LPWN = 21

    @MOD_LPWn.setter
    def MOD_LPWn(self, state):
        self.dout_set(21, state) # H_LPWN_OE_N = 21
        # self.dout_set(21, state) # MCU_MOD_LPWN = 21

    @property
    def MOD_RSTn(self):
        return not self.dout(22) # MOD_RSTN = 3

    @MOD_RSTn.setter
    def MOD_RSTn(self, state):
        self.dout_set(22, not state) # H_RSTN_OE_N = 22
        # self.dout_set(20, state) # MCU_MOD_RSTN = 20

    def reset_module(self):
        self.MOD_RSTn = True
        self.MOD_RSTn = False
        time.sleep(5)

    def cdb1_idle(self):
        status = self.twi_rr(37)
        return not (status & 0x80)

    def cdb1_cip(self):
        time.sleep(0.1)
        status = self.twi_rr(37)
        # print("cip 0x%4x.\n" % status)
        # return bool(status & 0x80)
        return bool((status & 0x80) or (status == 0))

    def cdb1_success(self):
        status = self.twi_rr(37)
        # print('cdb reg37 status %d.\n' % status)
        return not (status & 0xC0)

    def cdb_chkcode(self, vals):
        chkcode = ctypes.c_ubyte(0)
        for b in vals:
            chkcode.value += b
        chkcode.value = - chkcode.value - 1
        return chkcode.value

    def cdb_psw(self): # Vendor password Write CDB password: 0xa5, 0x5a, 0x5a, 0xa5 to lower memory byte 122~125
        self.twi_sbw(122, b'\xa5\x5a\x5a\xa5')

    def cdb_user_psw(self):
        self.twi_sbw(122, b'\x00\x00\x10\x11')


    def get_module_state(self):
        a = Apis()
        module_state_map = {
            '000': 'Reserved',
            '001': 'LowPwr',
            '010': 'PwrUp',
            '011': 'Ready',
            '100': 'PwrDn',
            '101': 'Fault',
            '110': 'Reserved',
            '111': 'Reserved'
        }
        ret = a.get_twi(1, 0x3)
        ret1 = ret.split(',')[0]  #hex
        ret2 = int(ret1, 16)

        idx = '{:08b}'.format(ret2)[4:7]
        return idx + ',' + module_state_map[idx]


    def get_dp_state(self):
        from .cmis import CMIS
        dp_state_map = {
            1: 'DataPathDeactivated State',
            2: 'DataPathInit State',
            3: 'DataPathDeinit State',
            4: 'DataPathActivated State',
            5: 'DataPathTxTurnOn State',
            6: 'DataPathTxTurnOff State',
            7: 'DataPathInitialized State'
        }

        c = CMIS(self)
        dp_state = c.dp_state
        # print(dp_state)
        # print(type(dp_state))
        if dp_state < 1 or dp_state > 7:
            return 'Reserved'
        else:
            return str(dp_state) + ", " + dp_state_map[dp_state]


    # The examples of reading the following parameters
    def get_module_parameters(self):
        setdefaulttimeout(200000)
        from .ain import Ain
        from .aout import Aout
        from .cmis import CMIS
        from .abc import ABC
        from .ddm import DDM

        self.cdb_pswdw()
        print('==================' + "Module parameters".upper() + '===================')
        print('Tx Driver VOFE Current：{}'.format( Ain(self, 'VOFE_CURRENT_SEN').aval ))
        print('')
        print('Tx MZM Bias 6 MZs')
        print('------------------'*3)
        print('MCU2_TXIH1_DC:\t\t{}'.format((Aout(self, 'MCU2_TXIH1_DC').aval)))
        print('MCU2_TXQH1_DC:\t\t{}'.format((Aout(self, 'MCU2_TXQH1_DC').aval)))
        print('MCU2_TXPH1_DC:\t\t{}'.format((Aout(self, 'MCU2_TXPH1_DC').aval)))
        print('MCU2_TYIH1_DC:\t\t{}'.format((Aout(self, 'MCU2_TYIH1_DC').aval)))
        print('MCU2_TYQH1_DC:\t\t{}'.format((Aout(self, 'MCU2_TYQH1_DC').aval)))
        print('MCU2_TYPH1_DC:\t\t{}'.format((Aout(self, 'MCU2_TYPH1_DC').aval)))

        print('')
        print('Tx MZM ABC Demod')
        print('------------------'*3)
        abc = ABC(self)
        print('XP:\t\t{}'.format( abc.curr_demod(0) ))
        print('XI:\t\t{}'.format( abc.curr_demod(1) ))
        print('XQ:\t\t{}'.format( abc.curr_demod(2) ))
        print('YP:\t\t{}'.format( abc.curr_demod(3) ))
        print('YI:\t\t{}'.format( abc.curr_demod(4) ))
        print('YQ:\t\t{}'.format( abc.curr_demod(5) ))

        print('Tx Drive VOFE voltage:\t{}'.format( Ain(self, 'P5V8_DRIVER_VOFE').aval ))
        print('Tx Driver_VT:\t\t{}'.format( Aout(self, 'DRIVER_VT').aval ))

        print('')
        print('Tx VOA current')
        print('------------------'*3)
        print('MCU1_TX_VOA_X:\t\t{}'.format( Aout(self, 'MCU1_TX_VOA_X').aval ))
        print('MCU1_TX_VOA_Y:\t\t{}'.format( Aout(self, 'MCU1_TX_VOA_Y').aval ))

        print('')
        print('Rx TIA VGC 4ch')
        print('------------------'*3)
        print('ADC_TIA_VGC_XI:\t\t{}'.format( Ain(self, 'ADC_TIA_VGC_XI').aval ))
        print('ADC_TIA_VGC_XQ:\t\t{}'.format( Ain(self, 'ADC_TIA_VGC_XQ').aval ))
        print('ADC_TIA_VGC_YI:\t\t{}'.format( Ain(self, 'ADC_TIA_VGC_YI').aval ))
        print('ADC_TIA_VGC_YQ:\t\t{}'.format( Ain(self, 'ADC_TIA_VGC_YQ').aval ))

        print('')
        print('Rx VOA current')
        print('------------------'*3)
        print('DAC_RX_VOA_X:\t\t{}'.format( Aout(self, 'DAC_RX_VOA_X').aval ))
        print('DAC_RX_VOA_Y:\t\t{}'.format( Aout(self, 'DAC_RX_VOA_Y').aval ))


        print('')
        print('DDM preFEC BER ')
        print('------------------'*3)
        cmis = CMIS(self)
        ddm = DDM(self)
        print('media prefec Current0\t\t{}'.format( cmis.vdm_decode['media prefec Current0']  ))
        print('media postfec Current0:\t\t{}'.format( cmis.vdm_decode['media postfec Current0'] ))
        print('host prefec Current0:\t\t{}'.format( cmis.vdm_decode['host prefec Current0']  ))
        print('host postfec Current0:\t\t{}'.format( cmis.vdm_decode['host postfec Current0'] ))
        print('DDM Rx channel power monitor:\t\t{}'.format( cmis.vdm_decode['Rx Sig Power'] ))
        print('DDM Rx total power monitor:\t\t{}'.format( cmis.vdm_decode['Rx Total Power'] ))
        print('DDM Case tempeature:\t\t{}'.format( ddm.case_temp ))
        print('DDM Tx output power monitor:\t\t{}'.format( cmis.vdm_decode['Tx Power'] ))



